package com.sunkyc.framework.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunkyc.commons.exception.CustomerException;
import com.sunkyc.framework.system.CacheKey.AuthroticationCacheKeys;
import com.sunkyc.framework.system.CacheKey.SystemCacheKeys;
import com.sunkyc.framework.system.entity.SysDept;
import com.sunkyc.framework.system.entity.SysDeptAncestors;
import com.sunkyc.framework.system.entity.SysUser;
import com.sunkyc.framework.utils.RedisUtils;
import com.sunkyc.framework.system.mapper.SysDeptMapper;
import com.sunkyc.framework.system.service.SysDeptAncestorsService;
import com.sunkyc.framework.system.service.SysDeptService;
import com.sunkyc.framework.system.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * 部门表 服务实现类
 * </p>
 *
 * @author sunkyc
 * @since 2022-05-31
 */
@Service
@RequiredArgsConstructor
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> implements SysDeptService {
    private final SysDeptMapper baseMapper;
    private final RedisUtils redisUtils;
    private final SysUserService sysUserService;
    private final SysDeptAncestorsService ancestorsService;

    @Override
    public List<SysDept> treeList() {
        String key = SystemCacheKeys.DEPT_DATA + "_tree_list";
        List<SysDept> list = redisUtils.getCacheList(key);
        if (CollectionUtil.isNotEmpty(list)) return list;
        Long minParentId = baseMapper.minParentId();
        list = baseMapper.selectList(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getParentId, minParentId));
        if (CollectionUtil.isNotEmpty(list)) {
            for (SysDept sysDept : list) {
                setChildren(sysDept);
            }
            redisUtils.setCacheList(key, list);
        }
        return list;
    }

    @Override
    public List<SysDept> deptListByParentId(Long deptId) {
        String key = SystemCacheKeys.DEPT_DATA + "_by_parent_list_#" + deptId;
        List<SysDept> list = redisUtils.getCacheList(key);
        if (CollectionUtil.isNotEmpty(list)) return list;
        list = baseMapper.selectList(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getParentId, deptId));
        if (CollectionUtil.isNotEmpty(list)) redisUtils.setCacheList(key, list);
        return list;
    }

    @Override
    @Transactional
    public int addDept(SysDept sysDept) {
        // 获取父级组织的组织结构列表
        int count = baseMapper.insert(sysDept);
        if (count > 0) {
            List<SysDeptAncestors> ancestors = initAncestorsByDept(sysDept);
            ancestors.forEach(item->{
                SysDeptAncestors sysDeptAncestors = new SysDeptAncestors().setDeptId(sysDept.getDeptId())
                        .setDeptAncestorId(item.getDeptAncestorId());
                ancestorsService.save(sysDeptAncestors);
            });
            redisUtils.deleteByPrefix(SystemCacheKeys.DEPT_DATA);
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        }
        return count;
    }


    private List<SysDeptAncestors> initAncestorsByDept(SysDept sysDept){
        List<SysDeptAncestors> sysDeptAncestors = ancestorsService.queryListByDeptId(sysDept.getParentId());
        if(CollectionUtils.isEmpty(sysDeptAncestors)){
            sysDeptAncestors = new ArrayList<>();
        }
        sysDeptAncestors.add(new SysDeptAncestors().setDeptId(sysDept.getDeptId())
                .setDeptAncestorId(sysDept.getParentId()));
        return sysDeptAncestors;
    }




    @Override
    @Transactional
    public int updateDept(SysDept sysDept) {
        if(ancestorsService.checkedIsChildren(sysDept.getDeptId(),sysDept.getParentId())){
            throw new CustomerException("别搞 SOA 操作！");
        }
        SysDept dbDept = baseMapper.selectById(sysDept.getDeptId());
        if(baseMapper.exists(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getParentId,sysDept.getDeptId()))){
            if(!dbDept.getParentId().equals(sysDept.getParentId())){
                throw new CustomerException("请先设置或移除子部门组织再进行操作");
            }
        }
        int count = baseMapper.updateById(sysDept);
        if (count > 0) {
            ancestorsService.delByDeptId(sysDept.getDeptId());
            List<SysDeptAncestors> ancestors = initAncestorsByDept(sysDept);
            ancestors.forEach(item->{
                SysDeptAncestors sysDeptAncestors = new SysDeptAncestors().setDeptId(sysDept.getDeptId())
                        .setDeptAncestorId(item.getDeptAncestorId());
                ancestorsService.save(sysDeptAncestors);
            });
            redisUtils.deleteByPrefix(SystemCacheKeys.DEPT_DATA);
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        }
        return count;
    }

    @Override
    @Transactional
    public int delDeptByIds(Long[] ids) {
        // 校验是否存在子部门
        for (Long id : ids) {
            if (this.count(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getParentId, id)) > 0) {
                throw new CustomerException("该组织下存在下级组织，请检查");
            }
            if (sysUserService.count(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getDeptId, id)) > 0) {
                throw new CustomerException("请检查该组织下成员信息再删除");
            }
            ancestorsService.delByDeptId(id);
        }
        int count = baseMapper.deleteBatchIds(Arrays.asList(ids));
        if (count > 0) {
            redisUtils.deleteByPrefix(SystemCacheKeys.DEPT_DATA);
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        }
        return count;
    }

    @Override
    public List<Long> querySelfAndChildrenIds(Long deptId) {
        String key = SystemCacheKeys.DEPT_DATA + "_ids_list_" + deptId;
        List<Long> longs = redisUtils.getCacheList(key);
        if (CollectionUtils.isNotEmpty(longs)) return longs;
        longs = ancestorsService.queryChildrenIds(deptId);
        longs.add(0,deptId);
        if (CollectionUtils.isNotEmpty(longs)) redisUtils.setCacheList(key, longs);
        return longs;
    }


    private void setChildren(SysDept sysDept) {
        List<SysDept> sysDepts = baseMapper.selectList(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getParentId, sysDept.getDeptId()));
        if (CollectionUtil.isNotEmpty(sysDepts)) {
            for (SysDept dept : sysDepts) {
                setChildren(dept);
            }
            sysDept.setChildren(sysDepts);
        }
    }
}
